package com.briup.bookstore.service.impl;

import com.briup.bookstore.common.constant.OrderConstant;
import com.briup.bookstore.common.exception.ServiceException;
import com.briup.bookstore.common.response.ResultCode;
import com.briup.bookstore.common.security.SecurityContext;
import com.briup.bookstore.domain.bean.Order;
import com.briup.bookstore.domain.bean.OrderItem;
import com.briup.bookstore.domain.bean.User;
import com.briup.bookstore.domain.dto.OrderCreateDTO;
import com.briup.bookstore.domain.po.ShopcarPO;
import com.briup.bookstore.domain.vo.OrderDetailVO;
import com.briup.bookstore.domain.vo.OrderItemVO;
import com.briup.bookstore.domain.vo.OrderVO;
import com.briup.bookstore.mapper.OrderMapper;
import com.briup.bookstore.mapper.ShopcarMapper;
import com.briup.bookstore.service.BookService;
import com.briup.bookstore.service.OrderItemService;
import com.briup.bookstore.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final OrderMapper orderMapper;
    private final ShopcarMapper shopcarMapper;
    private final OrderItemService orderItemService;
    private final BookService bookService;

    @Override
    public List<OrderVO> queryByConditional(String id, Integer status) {
        // 获取当前登录用户对象
        User currentUser = SecurityContext.currentUser();
        // 根据条件查询订单数据
        List<OrderVO> orderVOList = orderMapper
                .queryByConditional(currentUser.getId(), id, status);
        // 处理查询结果
        orderVOList.forEach(orderVO ->
                orderVO.setUsername(currentUser.getUsername())
        );
        // 返回处理后的订单VO列表
        return orderVOList;
    }

    @Override
    public OrderDetailVO queryById(String orderId) {
        // 必须保证数据是当前登录用户的订单详情数据
        User user = SecurityContext.currentUser();
        OrderDetailVO detailVO = orderMapper
                .queryDetailById(user.getId(), orderId);
        detailVO.setUsername(user.getUsername());
        // 计算订单总金额和商品总数量
        detailVO.setTotalNum(0);
        detailVO.setTotalPrice(0.0);
        detailVO.getOrderItems()
                .forEach(orderItemVO -> {
                    detailVO.setTotalNum(
                            detailVO.getTotalNum() + orderItemVO.getNum());
                    detailVO.setTotalPrice(
                            detailVO.getTotalPrice() + orderItemVO.getTotalPrice());
                });
        return detailVO;
    }

    @Override
    @Transactional
    public void addOrder(OrderCreateDTO orderCreateDTO) {
        Integer userId = SecurityContext.userId();
        // 1. 转换为订单实体
        Order order = convertToOrder(orderCreateDTO);
        // 2. 保存订单数据
        orderMapper.saveOrder(order);
        // 3. 先校验对应的购物车商品是否存在
        List<Integer> shopCartIds = orderCreateDTO.getShopCarIds();
        List<ShopcarPO> shopcars = shopcarMapper.queryByIdsWithUserId(shopCartIds, userId);
        // 校验购物车商品是否存在，并且保证购物车商品个数与订单商品个数一致；
        // 要求购物车中所选图书的状态必须为上架状态
        if (CollectionUtils.isEmpty(shopcars) ||
            shopcars.size() != shopCartIds.size()) {
            throw new ServiceException(ResultCode.ORDER_SHOPCAR_NOT_EXIST);
        }
        // 4. 将购物车项列表 转化为 订单项列表
        List<OrderItem> orderItems = shopcars.stream()
                .map(shopcar ->
                        convertToOrderItem(order.getId(), shopcar))
                .toList();
        // 5. 保存订单项数据
        orderItemService.saveOrderItems(orderItems);
        // 6. 删除购物车项数据
        shopcarMapper.deleteShopcarItem(shopCartIds, userId);
    }

    @Override
    public void closeOrder(String orderId) {
        // 1. 校验订单是否存在
        OrderDetailVO detailVO = checkOrderStatus(orderId);
        // 2. 如果订单存在，那么应该先去添加订单中对应商品的数量到图书库存中
        Map<Integer, Integer> bookIdToNumMap = detailVO.getOrderItems().stream()
                .collect(Collectors.toMap(
                        OrderItemVO::getBookId,
                        OrderItemVO::getNum));
        bookService.updateStock(bookIdToNumMap);

        // 3. 修改订单状态为关闭
        updateOrderStatus(detailVO, OrderConstant.CREATED_UNPAID, OrderConstant.CANCELED);
    }

    @Override
    public void completeOrder(String orderId) {
        // 1. 校验订单是否存在
        OrderDetailVO detailVO = checkOrderStatus(orderId);
        // 2. 修改状态
        updateOrderStatus(detailVO, OrderConstant.SHIPPED_UNCONFIRMED,
                OrderConstant.CONFIRMED_COMPLETED);
    }

    private OrderDetailVO checkOrderStatus(String orderId) {
        Integer userId = SecurityContext.userId();
        // 1. 校验订单是否存在
        OrderDetailVO detailVO = orderMapper.queryDetailById(userId, orderId);
        if (detailVO == null) {
            throw new ServiceException(ResultCode.ORDER_NOT_EXIST);
        }
        return detailVO;
    }

    /**
     * 更新订单状态
     *
     * @param orderVO     订单VO实体
     * @param beforeStaus 订单之前的状态
     * @param afterStatus 订单之后的状态
     */
    private void updateOrderStatus(OrderVO orderVO, OrderConstant beforeStaus,
                                   OrderConstant afterStatus) {
        // 校验订单状态是否符合要求
        if (orderVO.getStatus() != beforeStaus.getStatus()) {
            throw new ServiceException(ResultCode.ORDER_STATUS_ERROR);
        }
        // 如果订单的前置状态无误，那么就可以更新订单状态
        // 更新订单状态
        orderMapper.updateStatus(orderVO.getOrderId(), afterStatus.getStatus());
    }

    /**
     * 将购物车项转换为订单项
     *
     * @param orderId 订单ID
     * @param shopcar 购物车项
     * @return 订单项实体
     */
    private OrderItem convertToOrderItem(String orderId, ShopcarPO shopcar) {
        // 构建并返回订单项实体
        return OrderItem.builder()
                .orderId(orderId)
                .bookId(shopcar.getBookId())
                .num(shopcar.getNum())
                .finalPrice(shopcar.getPrice())
                .build();
    }

    /**
     * 将订单创建DTO转换为订单实体
     *
     * @param orderCreateDTO 订单创建DTO
     * @return 订单实体
     */
    private Order convertToOrder(OrderCreateDTO orderCreateDTO) {
        // 构建并返回订单实体
        return Order.builder()
                .id(generateOrderId())
                .userId(SecurityContext.userId())
                // 订单创建时间设置为当前时间
                .createDate(LocalDateTime.now())
                // 订单状态设置为已创建未支付
                .status(OrderConstant.CREATED_UNPAID.getStatus())
                // 从订单创建DTO中获取收货人姓名、收货地址、收货人手机号
                .receiveUsername(orderCreateDTO.getReceiveUsername())
                .receiveAddress(orderCreateDTO.getReceiveAddress())
                .receivePhone(orderCreateDTO.getReceivePhone())
                .build();
    }

    /**
     * 生成订单编号
     *
     * @return 订单编号
     */
    private String generateOrderId() {
        // 生成订单编号
        return "briup" + UUID.randomUUID().toString().replace("-", "");
    }
}
